#include "chi.h"
#include "ui_chi.h"
#include "textchunk.h"
#include <QListWidgetItem>
#include <QMessageBox>
#include <QString>
#include <QtNetwork/QTcpSocket>
#include <QHash>

Chi::Chi(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Chi)
{
    ui->setupUi(this);
    QPalette p = ui->txtMain->palette();
    p.setColor(QPalette::Base, QColor(0, 0, 0));
    ui->txtMain->setPalette(p);
    ui->txtMain->setTextColor(QColor(255, 255, 255));
    ui->txtRaw->setVisible(false);
    ui->txtMain->setFocus();
    printCommands();

    defaultColor = "lightgrey";
    autoTimer = new QTimer();

    tcpSocket = new QTcpSocket(this);
    connect(tcpSocket, SIGNAL(connected()), this, SLOT(connected()));
    connect(tcpSocket, SIGNAL(disconnected()), this, SLOT(disconnected()));
    connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(read_data()));
    connect(tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error()));
    connect(ui->txtCommand, SIGNAL(numpadKeyPressed(int)), this, SLOT(myLineEditKeyPressed(int)));
    connect(ui->txtCommand, SIGNAL(ctrlKeyComboPressed(QString)), this, SLOT(myLineEditCtrlComboPressed(QString)));
    connect(autoTimer, SIGNAL(timeout()), this, SLOT(autoCure()));
}

Chi::~Chi()
{
    delete ui;
}

void Chi::autoCure()
{
    if (tcpSocket->state() == QAbstractSocket::ConnectedState)
    {
        QString str = "cure\r";
        tcpSocket->write(str.toAscii().data(), str.length() + 1);
        appendHtml(">> autocure\n", "purple", false, false);
    }
}

void Chi::on_txtCommand_returnPressed()
{
    QString str = ui->txtCommand->text();

    if (str.startsWith("/"))
    {
        if (str == "/connect")
        {
            connectToServer();
        }
        else if (str == "/disconnect" || str == "/quit")
        {
            disconnectFromServer();
        }
        else if (str == "/debug")
        {
            showDebug();
        }
        else if (str == "/help")
        {
            printCommands();
        }
        else if (str.startsWith("/fontsize="))
        {
            int size = str.mid(str.indexOf("=")+1).toInt();
            setFontSize(size);
        }
        else if (str == "/foo")
        {

        }
        else if (str == "/healthbars")
        {
            if (ui->sliMe->isVisible())
            {
                ui->sliMe->setVisible(false);
                ui->sliTarget->setVisible(false);
                ui->label->setVisible(false);
                ui->label_2->setVisible(false);
            }
            else
            {
                ui->sliMe->setVisible(true);
                ui->sliTarget->setVisible(true);
                ui->label->setVisible(true);
                ui->label_2->setVisible(true);
            }
        }
        else if (str == "/clear")
        {
            ui->txtMain->clear();
        }
        else if (str == "/autocure")
        {
            if (!autoTimer->isActive())
                autoTimer->start(7000);
            else
                autoTimer->stop();
        }
    }
    else
    {
        str += "\r";
        if (tcpSocket->state() == QAbstractSocket::ConnectedState)
        {
            tcpSocket->write(str.toAscii().data(), str.length() + 1);
            appendHtml("> " + ui->txtCommand->text() + "\n", "red", false, true);
        }
    }
    ui->txtCommand->selectAll();

    //ui->txtMain->setFontPointSize(ui->txtMain->fontPointSize() + 1);
}

void Chi::printCommands()
{
    QHash<QString, QString> hash;
    QStringList commandList;

    hash.insert("/clear", "clears the screen");
    commandList.append("/clear");
    hash.insert("/connect", "connects to server bat.org:23");
    commandList.append("/connect");
    hash.insert("/debug", "show raw data sent by server");
    commandList.append("/debug");
    hash.insert("/disconnect", "disconnects from server");
    commandList.append("/disconnect");
    hash.insert("/fontsize=<num>", "sets the fontsize to <num>");
    commandList.append("/fontsize=<num>");
    hash.insert("/help", "list of all the commands");
    commandList.append("/help");
    hash.insert("/quit", "disconnects from server");
    commandList.append("/quit");


    ui->txtMain->setTextColor(QColor("yellow"));
    ui->txtMain->append("*******************************************************");
    for (int i = 0; i < commandList.count(); i++)
    {
        moveCursorToEnd();
        ui->txtMain->append(commandList.at(i) + "\t\t" + hash.value(commandList.at(i)));
    }
    ui->txtMain->append("*******************************************************");
    ui->txtMain->ensureCursorVisible();
    ui->txtMain->setTextColor(QColor("white"));
}

void Chi::connected()
{
    appendHtml("\nconnected", defaultColor, false, true);
    formatRead = false;
}

void Chi::disconnected()
{
    appendHtml("\ndisconnected", defaultColor, false, true);
}

void Chi::read_data()
{
    int bufSize = 2048;
    char buffer[2048] = {0};
    char nullChar = 255;
    char escChar = 27;
    QStringList strList;
    QString col = defaultColor;
    bool bold = false;
    int myHealthCounter = 0;
    int curHP = 0;
    int maxHP = 0;
    bool myHealthRead = false;
//    QList<Textchunk> *list = new QList<Textchunk>();
//    Textchunk t("foo", "red", false);
//    list->append(t);

    //Read from socket to buffer
    tcpSocket->read(buffer, bufSize);

    readData += buffer;
    readData = readData.left(readData.indexOf(nullChar));

    strList = readData.split(escChar);

    ui->txtMain->setUpdatesEnabled(false);
    if (strList.count() == 1)
    {
        appendHtml(strList.at(0), defaultColor, false, false);
        readData = "";
    }
    else
    {
        if (!formatRead) //if the format was not previously complete, check again
        {
            QString str = strList.last();
            QString format = str.left(str.indexOf('m') + 1);
            formatRead = false;
            if (format.startsWith(91) && format.endsWith(109)) // '[' && 'm'
            {
                formatRead = true;
            }
        }

        if (formatRead) //format is complete
        {
            //reset formatRead
            formatRead = false;

            //loop through all the textchunks (string and format)
            for (int i = 0; i < strList.count(); i++)
            {
                col = defaultColor;
                QString str = strList.at(i);
                QString format = str.left(str.indexOf('m') + 1);
                if (format.startsWith(91) && format.endsWith(109)) // '[' && 'm'
                {
                    format.remove(109);
                    QStringList formats = format.split(';');
                    QString form1 = formats.at(0);
                    QString form2 = "";
                    if (formats.count() > 1)
                        form2 = formats.at(1);
                    form1.remove("[");

                    //********** Parse color format **********
                    if (format.contains("30"))
                        col = "gray";
                    else if (format.contains("31"))
                        col = "red";
                    else if (format.contains("32"))
                        col = "green";
                    else if (format.contains("33"))
                        col = "yellow";
                    else if (format.contains("34"))
                        col = "blue";
                    else if (format.contains("35"))
                        col = "magenta";
                    else if (format.contains("36"))
                        col = "cyan";
                    else if (format.contains("37"))
                        col = "white";
                    //********************

                    //********** Parse bold or normal **********
                    if (form1 == "0" || form2 == "0")
                    {
                        //toggle bold off
                        bold = false;
                    }
                    else if (form1 == "1" || form2 == "1")
                    {
                        //toggle bold on
                        bold = true;
                    }
                    //********************

                    //Remove format from string
                    str.remove(format + "m");

                    //********** My health bar **********
                    if (!myHealthRead)
                    {
                        switch (myHealthCounter)
                        {
                        case 0:
                            bool ok;
                            int tmpHP;
                            tmpHP = str.toInt(&ok, 10);
                            if (ok)
                            {
                                curHP = tmpHP;
                                myHealthCounter++;
                            }
                            break;
                        case 1:
                            if (str.contains("(") && str.contains(")["))
                            {
                                int start = 1;
                                int last = str.indexOf(")");
                                int chars = last - start;
                                bool ok;
                                int tmpMaxHP = str.mid(1, chars).toInt(&ok, 10);
                                if (ok)
                                {
                                    maxHP = tmpMaxHP;
                                    myHealthCounter++;
                                }
                                myHealthRead = true;

                                int percentage = (curHP * 100) / maxHP;
                                ui->txtRaw->append(QString::number(curHP) + " / " + QString::number(maxHP) + " " + QString::number(percentage) + "%");
                                ui->sliMe->setValue(percentage);

                                break;
                            }

                        }
                    }
                    //********************

                    //********** Combat hilite **********
                    if (combatHilite(str))
                    {

                    }
                    //*******************

                    //********** Start the sleep counter (5 mins) **********
                    else if (str.contains("You lie down and begin to rest for a while."))
                    {
                        timer = new QTimer(this);
                        connect(timer, SIGNAL(timeout()), this, SLOT(updateSleep()));
                        sleepTimer = 60*5;
                        timer->start(1000);

                        appendHtml(str, col, bold, false);
                        readData = "";
                    }
                    //********************

                    //********** Print the string with the formatting **********
                    else
                    {
                        appendHtml(str, col, bold, false);
                    }
                    //********************

                    //********** Reset target slider **********
                    if (str.contains("DEAD, R.I.P."))
                    {
                        ui->sliTarget->setValue(0);
                    }
                    //********************
                }
                else
                {
                    appendHtml(str, col, bold, false);
                }
            }

            //reset readData
            readData = "";
        }
    }
    ui->txtMain->setUpdatesEnabled(true);
}

bool Chi::combatHilite(QString str)
{
    QString col = defaultColor;
    bool bold = false;

    if (str.contains("is in excellent shape"))
    {
        QStringList lines = str.split("\r\n");
        if (lines.count() > 0)
        {
            QString tmpCol = col;
            for (int j = 0; j < lines.count(); j++)
            {
                if (lines.at(j).contains("is in excellent shape"))
                {
                    col = "cyan";
                    setTargetHealth(lines.at(j));
                }
                else
                    col = tmpCol;

                appendHtml(lines.at(j), col, bold, false);
                if (j != lines.count() - 1)
                    ui->txtMain->insertPlainText("\r\n");
            }
            return true;
        }
    }
    else if (str.contains("is in a good shape"))
    {
        QStringList lines = str.split("\r\n");
        if (lines.count() > 0)
        {
            QString tmpCol = col;
            for (int j = 0; j < lines.count(); j++)
            {
                if (lines.at(j).contains("is in a good shape"))
                {
                    col = "cyan";
                    bold = true;
                    setTargetHealth(lines.at(j));
                }
                else
                    col = tmpCol;

                appendHtml(lines.at(j), col, bold, false);
                if (j != lines.count() - 1)
                    ui->txtMain->insertPlainText("\r\n");
            }
            return true;
        }
    }
    else if (str.contains("is slightly hurt"))
    {
        QStringList lines = str.split("\r\n");
        if (lines.count() > 0)
        {
            QString tmpCol = col;
            for (int j = 0; j < lines.count(); j++)
            {
                if (lines.at(j).contains("is slightly hurt"))
                {
                    col = "green";
                    setTargetHealth(lines.at(j));
                }
                else
                    col = tmpCol;

                appendHtml(lines.at(j), col, bold, false);
                if (j != lines.count() - 1)
                    ui->txtMain->insertPlainText("\r\n");
            }
            return true;
        }
    }
    else if (str.contains("is noticeably hurt"))
    {
        QStringList lines = str.split("\r\n");
        if (lines.count() > 0)
        {
            QString tmpCol = col;
            for (int j = 0; j < lines.count(); j++)
            {
                if (lines.at(j).contains("is noticeably hurt"))
                {
                    col = "green";
                    bold = true;
                    setTargetHealth(lines.at(j));
                }
                else
                    col = tmpCol;

                appendHtml(lines.at(j), col, bold, false);
                if (j != lines.count() - 1)
                    ui->txtMain->insertPlainText("\r\n");
            }
            return true;
        }
    }
    else if (str.contains("is not in a good shape"))
    {
        QStringList lines = str.split("\r\n");
        if (lines.count() > 0)
        {
            QString tmpCol = col;
            for (int j = 0; j < lines.count(); j++)
            {
                if (lines.at(j).contains("is not in a good shape"))
                {
                    col = "yellow";
                    setTargetHealth(lines.at(j));
                }
                else
                    col = tmpCol;

                appendHtml(lines.at(j), col, bold, false);
                if (j != lines.count() - 1)
                    ui->txtMain->insertPlainText("\r\n");
            }
            return true;
        }
    }
    else if (str.contains("is in bad shape"))
    {
        QStringList lines = str.split("\r\n");
        if (lines.count() > 0)
        {
            QString tmpCol = col;
            for (int j = 0; j < lines.count(); j++)
            {
                if (lines.at(j).contains("is in bad shape"))
                {
                    col = "yellow";
                    bold = true;
                    setTargetHealth(lines.at(j));
                }
                else
                    col = tmpCol;

                appendHtml(lines.at(j), col, bold, false);
                if (j != lines.count() - 1)
                    ui->txtMain->insertPlainText("\r\n");
            }
            return true;
        }
    }
    else if (str.contains("is in very bad shape"))
    {
        QStringList lines = str.split("\r\n");
        if (lines.count() > 0)
        {
            QString tmpCol = col;
            for (int j = 0; j < lines.count(); j++)
            {
                if (lines.at(j).contains("is in very bad shape"))
                {
                    col = "red";
                    setTargetHealth(lines.at(j));
                }
                else
                    col = tmpCol;

                appendHtml(lines.at(j), col, bold, false);
                if (j != lines.count() - 1)
                    ui->txtMain->insertPlainText("\r\n");
            }
            return true;
        }
    }
    else if (str.contains("is near death"))
    {
        QStringList lines = str.split("\r\n");
        if (lines.count() > 0)
        {
            QString tmpCol = col;
            for (int j = 0; j < lines.count(); j++)
            {
                if (lines.at(j).contains("is near death"))
                {
                    col = "red";
                    bold = true;
                    setTargetHealth(lines.at(j));
                }
                else
                    col = tmpCol;

                appendHtml(lines.at(j), col, bold, false);
                if (j != lines.count() - 1)
                    ui->txtMain->insertPlainText("\r\n");
            }
            return true;
        }
    }

    return false;
}

void Chi::setTargetHealth(QString line)
{
    if (line.contains("(") && line.contains("%)"))
    {
        int start = line.indexOf("(") + 1;
        int last = line.indexOf("%)");
        int chars = last - start;
        QString percentage = line.mid(start, chars);
        int perc = percentage.toInt();
        ui->sliTarget->setValue(perc);
    }
}

void Chi::updateSleep()
{
    if (sleepTimer > 0)
    {
        sleepTimer--;
        int secs = 0;
        int mins = 0;
        if (sleepTimer > 59)
        {
            mins = sleepTimer / 60;
            secs = sleepTimer - mins * 60;
        }
        else
            secs = sleepTimer;

        QString minsStr = QString::number(mins);
        QString secsStr = "";
        if (secs < 10)
            secsStr = "0" + QString::number(secs);
        else
            secsStr = QString::number(secs);

        this->setWindowTitle("DUMtaB (" + minsStr + ":" + secsStr + ")");
    }
    else
    {
        timer->stop();
        this->setWindowTitle("DUMtaB");
    }

}

void Chi::error()
{
    appendHtml("\nerror: " + tcpSocket->errorString(), defaultColor, false, true);
}

void Chi::connectToServer()
{
    QString hostname = "bat.org";
    int port = 23;
    //tcpSocket = new QTcpSocket(this);
    tcpSocket->abort();
    ui->txtMain->clear();


    if (tcpSocket->state() == QAbstractSocket::UnconnectedState)
    {
        tcpSocket->connectToHost(hostname, port);
        appendHtml("connecting to " + hostname + " " + QString::number(port) + "...", "lightgrey", false, false);
    }
}

void Chi::disconnectFromServer()
{
    tcpSocket->disconnectFromHost();
    tcpSocket->close();
}

void Chi::showDebug()
{
    if (ui->txtRaw->isVisible())
        ui->txtRaw->setVisible(false);
    else
        ui->txtRaw->setVisible(true);
}

void Chi::moveCursorToEnd()
{
    QTextCursor cursor = ui->txtMain->textCursor();
    cursor.movePosition(QTextCursor::End);
    ui->txtMain->setTextCursor(cursor);
}

void Chi::setFontSize(int size)
{
    ui->txtMain->selectAll();
    ui->txtMain->setFontPointSize(size);
    ui->txtMain->moveCursor(QTextCursor::End);
}

void Chi::appendHtml(QString str, QString col, bool bold, bool rawHtml)
{
    QString fontWeight;
    QString ret = "";
    if (bold)
        fontWeight = "bold";
    else
        fontWeight = "normal";

    QByteArray ba = str.toAscii();

    for (int i = 0; i < ba.length(); i++)
    {
        if (ba.at(i) == 32)
            ret += "&nbsp;";
        else if (ba.at(i) == 60 && !rawHtml) // '<'
            ret += "&lt;";
        else if (ba.at(i) == 62 && !rawHtml) // '>'
            ret += "&gt;";
        else
            ret += ba.at(i);
    }

    ret.replace("\r\n", "<br>");

    moveCursorToEnd();
    //ui->txtMain->insertHtml("<span style='font-weight: " + fontWeight + "; color: " + col + "'>" + ba + "</span>");
    ui->txtMain->setTextColor(QColor(col));
    ui->txtMain->insertPlainText(str);
    ui->txtMain->ensureCursorVisible();
}

void Chi::on_pushButton_clicked()
{
    connectToServer();
}

void Chi::myLineEditKeyPressed(int num)
{
    QString str = "";
    switch (num)
    {
    case 0:
        str = "map\r";
        break;
    case 1:
        str = "southwest\r";
        break;
    case 2:
        str = "south\r";
        break;
    case 3:
        str = "southeast\r";
        break;
    case 4:
        str = "west\r";
        break;
    case 5:
        str = "look\r";
        break;
    case 6:
        str = "east\r";
        break;
    case 7:
        str = "northwest\r";
        break;
    case 8:
        str = "north\r";
        break;
    case 9:
        str = "northeast\r";
        break;
    }

    tcpSocket->write(str.toAscii().data(), str.length() + 1);
}

void Chi::myLineEditCtrlComboPressed(QString key)
{
    if (key == "b")
    {
        setFontSize(12);
    }
    else if (key == "s")
    {
        setFontSize(8);
    }
}
